package com.suray.wcs.service.pojo.rgv.rgv.protocol;

import com.suray.basic.wcs.utils.LoggerUtil;
import com.suray.wcs.res.enums.Order;
import com.suray.wcs.service.core.util.LongConnSendUtilLora;
import com.suray.wcs.service.pojo.Rgv;
import com.suray.wcs.service.pojo.rgv.extract.log.RgvExtractLog;
import com.suray.wcs.service.pojo.rgv.rgv.protocol.base.RgvBaseMessage;
import com.suray.wcs.service.pojo.rgv.rgv.protocol.exception.FrameLocationException;
import com.suray.wcs.service.pojo.rgv.rgv.protocol.exception.MessageCompleteException;
import com.suray.wcs.service.pojo.rgv.rgv.protocol.exception.MessageErrorException;
import com.suray.wcs.service.pojo.rgv.rgv.protocol.exception.SendMessageException;
import com.suray.wcs.service.pojo.rgv.rgv.protocol.message.*;
import com.suray.wcs.service.pojo.rgv.rgv.protocol.util.DebugCommType;
import com.suray.wcs.service.pojo.rgv.rgv.protocol.util.RgvDebugMessageType;
import com.suray.wcs.service.pojo.rgv.rgv.protocol.util.RgvMessageType;
import com.suray.wcs.service.pojo.rgv.rgv.protocol.util.RgvProtocolConfig;
import com.suray.wcs.service.util.WcsUtil;

import java.io.IOException;

public class RgvProtocol {

    private Rgv rgv;

    private int uncurrNum = 0;
    private int resnedNum = 0;

    public RgvProtocol(Rgv rgv) {
        this.rgv = rgv;
    }

    public synchronized RgvBaseMessage comm(RgvBaseMessage sendMessage) throws IOException {
        if (RgvExtractLog.extractRgvs.contains(rgv)) {
            return null;
        }

        RgvBaseMessage baseMessage = comm(sendMessage, RgvProtocolConfig.MAX_RESEND_NUM);

        return baseMessage;
    }

    public void changeCommSocket() throws IOException {
        LongConnSendUtilLora.changeSocket(rgv);
    }

    private RgvBaseMessage comm(RgvBaseMessage sendMessage, int resendCount) throws IOException, SendMessageException {
        try {
            send(sendMessage);

            if (sendMessage instanceof RgvFileSendMessage) {
                return receiveAction(sendMessage, RgvProtocolConfig.MAP_TIME_OUT_VALUE);
            } else {
                return receiveAction(sendMessage, RgvProtocolConfig.NORMAL_TIME_OUT_VALUE);
            }
        } catch (IOException | MessageErrorException ioException) {
            LongConnSendUtilLora.getSocketSendUtil(rgv).terminate();
            if (resendCount == 0) {
                uncurrNum++;
                if (uncurrNum % 30 == 0) {
                    LoggerUtil.error(rgv.getRgvName() + sendMessage.getDescription() + ",离线次数" + uncurrNum, this.getClass());
                }
                throw ioException;
            } else {
                WcsUtil.delay(1000);
                resendCount--;
                resnedNum++;
                if (uncurrNum % 30 == 0) {
                    LoggerUtil.error(rgv.getRgvName() + sendMessage.getDescription() + ",重发次数" + resnedNum, this.getClass());
                }
                return comm(sendMessage, resendCount);
            }
        } catch (NegativeArraySizeException e) {
            LongConnSendUtilLora.getSocketSendUtil(rgv).terminate();
            if (resendCount == 0) {
                uncurrNum++;
                LoggerUtil.error(rgv.getRgvName() + sendMessage.getDescription() + ",连接断开,离线次数" + uncurrNum, this.getClass());
                throw new NegativeArraySizeException("小车连接断开！请确认网络无异常后，进行故障恢复");
            } else {
                WcsUtil.delay(1000);
                resendCount--;
                resnedNum++;
                LoggerUtil.error(rgv.getRgvName() + sendMessage.getDescription() + ",连接断开, 重发次数" + resnedNum +
                        ", 小车当前坐标：" + rgv.getCurLocation() + "--" + sendMessage.toString(), this.getClass());
                return comm(sendMessage, resendCount);
            }
        }
    }

    private RgvBaseMessage receiveAction(RgvBaseMessage sendMessage, int timeOut) throws IOException {
        try {
            byte[] recData = receive(sendMessage.getDescription(), timeOut);
            RgvBaseMessage recMessage = calcWholeRecData(sendMessage, recData);
            return recMessage;
        } catch (IOException e) {
            throw e;
        }
    }

    /**
     * 接收数据分配
     *
     * @param recData
     */
    private RgvBaseMessage calcWholeRecData(RgvBaseMessage sendMessage, byte[] recData) throws IOException {
        RgvBaseMessage recMessage;
        try {
            if (sendMessage instanceof RgvTaskSendMessage) {
                recMessage = analyzeRecTaskMessage(recData, sendMessage.getMessageLife());
            } else if (sendMessage instanceof RgvLifeSendMessage) {
                recMessage = analyzeRecLiftMessage(recData, sendMessage.getMessageLife());
            } else if (sendMessage instanceof RgvCommandSendMessage) {
                recMessage = analyzeRecCommandMessage(recData, sendMessage.getMessageLife());
            } else if (sendMessage instanceof RgvFileSendMessage) {
                recMessage = analyzeRecMapMessage(recData, sendMessage.getMessageLife());
            } else if (sendMessage instanceof RgvSendLoraConfigMessage) {
                recMessage = analyzeRecLoraConfigMessage(recData, sendMessage.getMessageLife());
            } else if (sendMessage instanceof RgvSendScadaMessage) {
                recMessage = analyzeRecScadaMessage(recData, sendMessage.getMessageLife());
            } else if (sendMessage instanceof RgvDebugCmdSendMessage) {
                if (((RgvDebugCmdSendMessage) sendMessage).getSecondaryCmd() == 0) {
                    if (((RgvDebugCmdSendMessage) sendMessage).getCmd() == Order.GET_RES_VERSION.getOrderByte()) {
                        //读取res版本号
                        recMessage = analyzeRecDebugCommandMessage(recData, sendMessage.getMessageLife(),
                                ((RgvDebugCmdSendMessage) sendMessage).getCmd(), RgvDebugMessageType.READ_RES_VERSION);
                    } else {
                        //为0表示读取所有参数
                        recMessage = analyzeRecDebugCommandMessage(recData, sendMessage.getMessageLife(),
                                ((RgvDebugCmdSendMessage) sendMessage).getCmd(), RgvDebugMessageType.READ_ALL);
                    }
                } else {
                    recMessage = analyzeRecDebugCommandMessage(recData, sendMessage.getMessageLife(),
                            ((RgvDebugCmdSendMessage) sendMessage).getCmd(), RgvDebugMessageType.SIMPLE_READ);
                }
            } else {
                recMessage = analyzeRecNormalMessage(recData, sendMessage.getMessageLife());
            }
        } catch (FrameLocationException e) {
            LoggerUtil.warn(e.getMessage(), this.getClass());
            return receiveAction(sendMessage, RgvProtocolConfig.MESSAGE_CLEAR_TIME_OUT_VALUE);
        } catch (MessageCompleteException e) {
            LoggerUtil.warn(e.getMessage(), this.getClass());
            byte[] lastData = receive(sendMessage.getDescription(), RgvProtocolConfig.MESSAGE_CLEAR_TIME_OUT_VALUE);
            byte[] data = new byte[recData.length + lastData.length];
            System.arraycopy(recData, 0, data, 0, recData.length);
            System.arraycopy(lastData, 0, data, recData.length, lastData.length);
            return calcWholeRecData(sendMessage, data);
        }

        return recMessage;
    }

    private RgvBaseMessage analyzeRecScadaMessage(byte[] recData, Integer messageLife) throws IOException {
        RgvRecScadaMessage rgvRecScadaMessage = new RgvRecScadaMessage(rgv);
        rgvRecScadaMessage.checkMessage(recData, RgvMessageType.RGV_SCADA_MESSAGE, messageLife);
        return rgvRecScadaMessage;
    }

    private RgvBaseMessage analyzeRecLoraConfigMessage(byte[] recData, Integer messageLife) throws IOException {
        RgvRecLoraConfigMessage rgvRecLoraConfigMessage = new RgvRecLoraConfigMessage(rgv);
        rgvRecLoraConfigMessage.checkMessage(recData, RgvMessageType.RGV_CHANGE_LORA_MESSAGE, messageLife);
        return rgvRecLoraConfigMessage;
    }

    private RgvBaseMessage analyzeRecMapMessage(byte[] recData, Integer messageLife) throws IOException {
        RgvFileRecMessage rgvMapRecMessage = new RgvFileRecMessage(rgv);
        rgvMapRecMessage.checkMessage(recData, RgvMessageType.RGV_MAP_MESSAGE, messageLife);
        return rgvMapRecMessage;
    }

    private RgvBaseMessage analyzeRecNormalMessage(byte[] recData, Integer messageLife) throws IOException {
        RgvNormalRecMessage rgvMapRecMessage = new RgvNormalRecMessage(rgv, recData.length);
        return rgvMapRecMessage;
    }

    /**
     * 指令报文处理
     *
     * @param recData
     */
    private RgvCommandRecMessage analyzeRecCommandMessage(byte[] recData, Integer sendLife) throws IOException {
        RgvCommandRecMessage rgvCommandRecMessage = new RgvCommandRecMessage(rgv);
        rgvCommandRecMessage.checkMessage(recData, RgvMessageType.RGV_COMMAND_MESSAGE, sendLife);
        return rgvCommandRecMessage;
    }

    /**
     * 调试指令报文处理
     *  @param recData
     * @param debugMessageType
     */
    private RgvDebugCmdRecMessage analyzeRecDebugCommandMessage(byte[] recData, Integer sendLife, Integer cmd,
                                                                RgvDebugMessageType debugMessageType) throws IOException {
        if (cmd == DebugCommType.LIFT_PARAM.getcode()) {
            RgvDebugCmdRecMessage rgvDebugCmdRecMessage = new RgvDebugCmdRecMessage(rgv, DebugCommType.LIFT_PARAM
                    , debugMessageType);
            rgvDebugCmdRecMessage.checkMessage(recData, RgvMessageType.RGV_DEBUG_CMD_MESSAGE, sendLife);
            return rgvDebugCmdRecMessage;
        } else if (cmd == DebugCommType.RES_PARAM.getcode()) {
            RgvDebugCmdRecMessage rgvDebugCmdRecMessage = new RgvDebugCmdRecMessage(rgv, DebugCommType.RES_PARAM
                    , debugMessageType);
            rgvDebugCmdRecMessage.checkMessage(recData, RgvMessageType.RGV_DEBUG_CMD_MESSAGE, sendLife);
            return rgvDebugCmdRecMessage;
        } else if (cmd == DebugCommType.DRIVING_PARAM.getcode()){
            RgvDebugCmdRecMessage rgvDebugCmdRecMessage = null;
            rgvDebugCmdRecMessage = new RgvDebugCmdRecMessage(rgv, DebugCommType.DRIVING_PARAM, debugMessageType);
            rgvDebugCmdRecMessage.checkMessage(recData, RgvMessageType.RGV_DEBUG_CMD_MESSAGE, sendLife);
            return rgvDebugCmdRecMessage;
        } else if (cmd == DebugCommType.GET_RES_VERSION.getcode()) {
            RgvDebugCmdRecMessage rgvDebugCmdRecMessage = new RgvDebugCmdRecMessage(rgv, DebugCommType.RES_PARAM
                    , debugMessageType);
            rgvDebugCmdRecMessage.checkMessage(recData, RgvMessageType.RGV_DEBUG_CMD_MESSAGE, sendLife);
            return rgvDebugCmdRecMessage;
        } else {
            RgvDebugCmdRecMessage rgvDebugCmdRecMessage = new RgvDebugCmdRecMessage(rgv, DebugCommType.SET_ONE_PARAM);
            rgvDebugCmdRecMessage.checkMessage(recData, RgvMessageType.RGV_DEBUG_CMD_MESSAGE, sendLife);
            return rgvDebugCmdRecMessage;
        }
    }

    /**
     * 心跳报文处理
     *
     * @param recData
     */
    private RgvLifeRecMessage analyzeRecLiftMessage(byte[] recData, Integer sendLife) throws IOException {
        RgvLifeRecMessage rgvLifeRecMessage = new RgvLifeRecMessage(rgv);
        rgvLifeRecMessage.checkMessage(recData, RgvMessageType.RGV_LIFE_MESSAGE, sendLife);
        return rgvLifeRecMessage;
    }

    /**
     * 任务报文处理
     *
     * @param recData
     */
    private RgvTaskRecMessage analyzeRecTaskMessage(byte[] recData, Integer sendLife) throws IOException {
        RgvTaskRecMessage rgvTaskMessage = new RgvTaskRecMessage(rgv);
        rgvTaskMessage.checkMessage(recData, RgvMessageType.RGV_TASK_MESSAGE, sendLife);
        return rgvTaskMessage;
    }

    private void analyzeSendData(RgvBaseMessage sendMessage) {
        try {
            if (sendMessage instanceof RgvTaskSendMessage) {
                analyzeSendTaskMessage((RgvTaskSendMessage) sendMessage);
            } else if (sendMessage instanceof RgvCommandSendMessage) {
                analyzeSendCommandMessage((RgvCommandSendMessage) sendMessage);
            } else if (sendMessage instanceof RgvLifeSendMessage) {
                analyzeSendLifeMessage((RgvLifeSendMessage) sendMessage);
            } else if (sendMessage instanceof RgvFileSendMessage) {
                analyzeSendMapMessage((RgvFileSendMessage) sendMessage);
            } else if (sendMessage instanceof RgvDebugCmdSendMessage) {
                analyzeRgvDebugCmdSendMessage((RgvDebugCmdSendMessage) sendMessage);
            }else {
                analyzeSendNormalMessage(sendMessage);
            }
        } catch (SendMessageException e) {
            throw e;
        }

    }

    private void analyzeSendNormalMessage(RgvBaseMessage sendMessage) {

    }

    private void analyzeSendMapMessage(RgvFileSendMessage sendMessage) {

    }

    private void analyzeRgvDebugCmdSendMessage(RgvDebugCmdSendMessage sendMessage) {

    }

    private void analyzeSendTaskMessage(RgvTaskSendMessage taskSendMessage) {
        taskSendMessage.analyzeTaskMessage();
    }

    private void analyzeSendLifeMessage(RgvLifeSendMessage lifeSendMessage) {
        lifeSendMessage.analyzeLifeMessage();
    }

    private void analyzeSendCommandMessage(RgvCommandSendMessage commandSendMessage) {
        commandSendMessage.analyzeCommandMessage();
    }

    private void send(RgvBaseMessage sendMessage) throws IOException {
        analyzeSendData(sendMessage);
        LongConnSendUtilLora lora = LongConnSendUtilLora.getSocketSendUtil(rgv);

        lora.send(sendMessage.makeMessage(), sendMessage.getDescription());
    }

    private byte[] receive(String des, int timeOut) throws IOException {
        return LongConnSendUtilLora.getSocketSendUtil(rgv).getReturnBytes(des, timeOut);
    }
}
